package com.examsys.service;

import java.lang.reflect.Method;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JDialog;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.examsys.po.Admin;
import com.examsys.po.Users;
import com.examsys.view.LoginDialog;
/**
 * 系统入口类
 * @author edu-1
 *
 */
public class Main {

	//业务逻辑层对象及数据访问层对象创建好后存入这个Map中
	public static Map<String, Object> beans = new HashMap<String, Object>();
	public static Admin admin;//存放登录成功的管理员对象
	public static Users users;//存放登录成功的考试者对象
	/**
	 * 获取业务逻辑层对象
	 * @param serviceName//存的是"adminRolesService"
	 * @return
	 * @throws Exception
	 */
	public static <T> T lookUp(String serviceName) throws Exception {
		AbstractBaseService service =(AbstractBaseService)beans.get(serviceName);
		if (service == null) {
			
			try {
				URL resource = Main.class.getResource("init.xml");//加载XML文件,要求init.xml文件与Main类在同一个包中
				
				String file=resource.getFile();
				//System.out.println(file);
				// 步骤1：实例化 DOM解析器(XML解析器)、
				DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
				
				//设置验证型的解析器（默认为非验证）			
				DocumentBuilder parser = factory.newDocumentBuilder();
				
				// 步骤2：开始解析XML
				// 调用次方法后，DOM解析器将XML文档载入进内存创建一棵树，
				// 返回的是这棵树的文档节点（在java中用接口Document表示）
				Document document = parser.parse(file);
				
				//根据ID获得指定的元素节点,serviceName="adminRolesService"
				Node node = getNodeById(serviceName, document);
				System.out.println("解新XML完毕");
				if(node==null){
					return null;//xml中没有配置要查找的业务逻辑层对象
				}
				NamedNodeMap attributes = node.getAttributes();//指定的元素节点的所有属性
				
				String className = attributes.getNamedItem("class").getNodeValue();//通过属性名"class"拿到类的完整名称
				//用反射创建业务逻辑层对象,默认调用业务层的空参构造方法
				service =(AbstractBaseService) Class.forName(className).newInstance();
				
				NodeList nodeList=node.getChildNodes();//获取所有的子元素
				System.out.println("完成主对象的构建");
				for(int i=0;i<nodeList.getLength();i++){
			    	//获得每一个property节点
					
					Node cnd = nodeList.item(i);//第i个子元素
					if(cnd.getNodeName().equals("property")){
						
						NamedNodeMap propertyAttributes = cnd.getAttributes();//获取属性列表
				    	Node nameNode=propertyAttributes.getNamedItem("name");//获得单个属性对象
				    	String name=nameNode.getNodeValue();//获得单个属性的值,dao
				    	Node refNode=propertyAttributes.getNamedItem("ref");//获得单个属性对象
				    	String ref=refNode.getNodeValue();//获得单个属性的值,adminRolesDao
				    	
				    	Object dao = beans.get(ref);//再通键adminRolesDao从容器中拿对象
				    	
				    	if(dao==null){//如果没拿到对象，说明还没有创建该对象
				    		
				    		//根据ID获得指定的元素节点,ref="adminRolesDao"
							node=getNodeById(ref, document);
							
							if(node==null){//如果没有找到id为adminRolesDao元素，说明还没在xml里配置
								return null;//直接返回空对象给调用者
							}
							
							attributes = node.getAttributes();//获取属性列表
							
							className = attributes.getNamedItem("class").getNodeValue();//通过class拿到类的完整名称
							//用反射创建数据访问层对象
							dao = Class.forName(className).newInstance();
							beans.put(ref, dao);//数据访问层对象放到集合中，方便下次直接拿出来用，不必再重复初始化
							System.out.println("完成主对象中属性对应的对象构建");
							
				    	}
				    	//System.out.println(dao.getClass().getInterfaces());
			    		//通过属性名构造set方法名,setDao
			    		String methodName="set"+name.substring(0, 1).toUpperCase()+name.substring(1,name.length());
			    		Method method = service.getClass().getMethod(methodName, dao.getClass().getInterfaces());//通过方法找到方法对象
			    		method.invoke(service,dao);//调用set方法给属性赋值
			    		System.out.println("完成主对象中各属性的初始化");
					}
			    	
			    }
				
				//存储业务逻辑层对象方便后面再使用
				beans.put(serviceName, service);
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception("没有所需要的业务逻辑层对象");
			}
		}
		return (T) service;
	}
	
	/**
	 * 通过id查找元素
	 * @param id 如："adminRolesService","adminRolesDao"
	 * @param document
	 * @return
	 */
	private static Node getNodeById(String id, Document document) {
		Node node=null;//存放想要查找的元素
		
		NodeList elements = document.getElementsByTagName("bean");//找出所有bean元素
		for(int i=0;i<elements.getLength();i++){//遍历所元素
			
			Node item = elements.item(i);//取出第i项元素
			NamedNodeMap attributes = item.getAttributes();//取出元素的所有属性
			Node n = attributes.getNamedItem("id");//只拿属性为id的项
			String nodeValue = n.getNodeValue();//拿属性中存的值
			if(nodeValue.equals(id)){//判断当前遍历的元素属性id是否与要查找的相等
				node = item;//把遍历到的元素给node变量
				break;
			}
			
		}
		return node;
	}
	
	/**
	 * 程序的入口方法
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			//创建登录对话框
			LoginDialog dialog = new LoginDialog();
			dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);//当点击关闭按钮时销毁窗口
			dialog.setVisible(true);//设置对话框为可见
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
